KeygenMe#1 by Marcus by mario

Cel: KeygenMe#1 by Marcus
Level: autor ocenia na Medium/Hard, ale to jak zawsze kwestia sporna..
Narzdzia: IDA, RSA-Tool
Data: 14.o3.2oo4

Intro
Prog spakowany FSG, nie zawiera adnych anti, tylko pure asm ;). Zanim zaczniemy, warto zajrze na www.witeg.prv.pl, obluka implementacje algorytmw szyfrujcych i poczyta nieco na temat RSA :].. Po gbszych ogldzinach widzimy, e jest troch tego :), wic podam przykad tylko jednego cryptoalgosa. Z innymi sami sobie poradzicie. Caoksztat keygenme do monotonny, ale warty uwagi, bo w pewnych momentach wymaga mylenia ;)

Let's go
adujemy proga do jakiego disassemblera i przechodzimy do tego kawaka kodu:

004095DF    push    [ebp+hDlg]
004095E2    call    GetDlgItemTextA        ; pobierz name
004095E7    cmp     eax, 3
004095EA    jb      loc_409AA4
004095F0    push    82h
004095F5    push    offset dword_4112CB
004095FA    push    65h
004095FC    push    [ebp+hDlg]
004095FF    call    GetDlgItemTextA        ; pobierz serial
00409604    cmp     eax, 0
00409607    jz      loc_409AA4
0040960D    mov     esi, offset dword_4112CB

Od 0040960D do 00409655 mamy konwersj seriala string->hex..

Nastpnie schodzimy niej, jak ju wspomniaem, jest tego nieco.. Wic na pocztek przykad:

00409655    mov     esi, offset dword_41134D   ; serial in hex
0040965A
0040965A loc_40965A:
0040965A    mov     eax, [esi]
0040965C    cmp     eax, 0
0040965F    jz      short loc_409679
00409661    sub     eax, 53554B41h
00409666    xor     eax, 44555041h
0040966B    add     eax, 4A415321h
00409670    bswap   eax
00409672    mov     [esi], eax
00409674    add     esi, 4
00409677    jmp     short loc_40965A
00409679
00409679
00409679 loc_409679:
00409679    mov     esi, offset dword_41134D

..czyli maa mielonka seriala..

0040967E    push    offset a012456789abcde  ;string
                            "012456789ABCDEFG"
00409683    call    sub_404374
00409688
00409688 loc_409688:
00409688    cmp     dword ptr [esi], 0
0040968B    jz      short loc_409699
0040968D    push    esi
0040968E    push    esi
0040968F    call    sub_404513
00409694    add     esi, 8
00409697    jmp     short loc_409688
00409699
00409699
00409699 loc_409699:
00409699    call    sub_404664

..jeli posuchae wczeniej mojej rady ;) to ju zapewne czaisz baz :>. Jak nie, to radz cignij sobie wszystkie implementacje algosw i obejrzyj je dokadnie, czym si rni, itd.. Jest to do masohistyczny sposb, ale po tak duej dawce adrenaliny, bdziesz rozpoznawa te algosy z odlegoci 2,5 kilmotera :].. Powyej mamy jedn z takich implementacji, jest to of coz IDEA, w idea.inc mamy:

invoke  IdeaExpandKey, ADDR _key       ;ustawienie klucza
                     ;raz ustawiony klucz moze byc wykorzystany kilka razy
                     ;klucz jest 'tracony' dla szyfrowania po wywolaniu
                     ;IdeaInvertKey lub IdeaClear
invoke  IdeaCrypt, ADDR _data_out, ADDR _data_in
invoke  IdeaClear    ;czyszczenie wewnetrznych danych
; uzyj tylko raz po zakonczeniu wszystkich czynnosci

IDEA szyfruje dane 8-blokowe, czyli w tym przypadku kade kolejne 8 bajtw danych jest szyfrowane za pomoc tego samego klucza (widzimy: add esi, 8), czyli klucz to string "012456789ABCDEFG", a dane do zaszyfrowania to serial(hex) po uprzedniej mielonce. Nastpnie znowu maa mielonka seriala (ju zaszyfrowanego, bo jest odczytywany i zapisywany cay czas w tym samym buforku)..

004096CF loc_4096CF:
004096CF    mov     esi, offset a012456789abcde ;
                                "012456789ABCDEFG"
004096D4    mov     eax, [esi]
004096D6    xor     eax, 12345678h
004096DB    add     eax, 45851254h
004096E0    mov     [esi], eax
004096E2    sub     eax, 12345678h
004096E7    add     eax, 45851254h
004096EC    mov     [esi+4], eax
004096EF    xor     eax, 12345678h
004096F4    sub     eax, 45851254h
004096F9    mov     [esi+8], eax
004096FC    sub     eax, 87654321h
00409701    xor     eax, 12345678h
00409706    add     eax, 45851254h
0040970B    mov     [esi+0Ch], eax

..tym razem modyfikowany jest sam klucz..

Kolejne operacje s praktycznie takie same: jakie algo szyfrujce -> mielonka seriala -> mielonka klucza itd.. My zatrzymamy si w tym miejscu:

00409851    push    offset dword_41134D
00409856    call    sub_409D7A           ; do eax leci dugo
0040985B    mov     ecx, eax             ; 'zmielonego' serial'a
0040985D    mov     esi, offset dword_41134D
00409862    mov     edi, offset dword_4113CF
00409867    call    sub_409CF9           ; konwersja hex(crypto(serial)) na hexstring
0040986C    push    0
0040986E    call    sub_409EA0
00409873    mov     [ebp+lpAddress], eax
00409876    push    0
00409878    call    sub_409EA0         ; here it comes :D
0040987D    mov     [ebp+var_C], eax
00409880    push    0
00409882    call    sub_409EA0
00409887    mov     [ebp+var_10], eax
0040988A    push    0
0040988C    call    sub_409EA0
00409891    mov     [ebp+var_8], eax

00409894    push    [ebp+lpAddress]
00409897    push    10h
00409899    push    offset a8ede4fc880fb9b ;"8EDE4FC880FB9B158D.."
0040989E    call    sub_40A043
004098A3    push    [ebp+var_8]
004098A6    push    10h
004098A8    push    offset a10001       ; "10001"
004098AD    call    sub_40A043
004098B2    push    [ebp+var_10]
004098B5    push    10h
004098B7    push    offset dword_4113CF ;hexstring(crypto(serial))
004098BC    call    sub_40A043

004098C1    push    [ebp+var_C]        ;C
004098C4    push    [ebp+lpAddress]    ;n
004098C7    push    [ebp+var_8]        ;e
004098CA    push    [ebp+var_10]       ;m
004098CD    call    sub_40AE54     ;powmod

004098D2    push    offset dword_4112CB
004098D7    push    [ebp+var_C]
004098DA    call    sub_40A274     ;zmiana C na hexstring

Czyli standard :)

Sygnaturka RSA:             C= m^e mod N<br>
A w naszym przypadku:       C= hexstring(crypto(serial)) ^ 10001 mod 8EDE4FC880FB9B15...

Myk polega na tym, e jest to RSA-2048 :] hehe.. Celem jest zrobienie keygena, wic jeeli chcemy to odwrci, musimy by w posiadaniu D (klucz prywatny). Faktoryzacja nie wchodzi w gr, czyli powinien istnie jaki backdoor :>, wrcimy do tego pniej..

..teraz jeszcze RSA musi po sobie posprzta..

004098DF    push    [ebp+lpAddress] ; lpAddress
004098E2    call    sub_409ECD
004098E7    push    [ebp+var_8]     ; lpAddress
004098EA    call    sub_409ECD
004098EF    push    [ebp+var_10]    ; lpAddress
004098F2    call    sub_409ECD
004098F7    push    [ebp+var_C]     ; lpAddress
004098FA    call    sub_409ECD

Nastpnie..

004098FF    push    offset String      ; name
00409904    call    sub_409D7A         ; do eax leci dlugosc z name
00409909    mov     ecx, eax
0040990B    mov     esi, offset String
00409910    mov     edi, offset dword_411203
00409915    call    sub_409CF9         ; hex(name) -> hexstring
0040991A    mov     eax, 48544221h
0040991F    movzx   ecx, ds:byte_40F5A7
00409926    imul    ecx, 5
00409929    div     ecx                ; hmm ;)

..pniej mamy kolejne szyfrowanie. Tym razem name'a w postaci hex..itd. (ehm czyli np. Name="mario" to hexstring="6D6172696F"), ale w tym wypadku mamy fajn sztuczk, z ktr btw. Zetknem si pierwszy raz :). Jadc nieco w d dochodzimy do miejsca, gdzie wywoywany jest ExitProcess, a zaraz przed nim co tam jest porwnywane :P z tym, e wynik porwnania daje nam taki sam rezultat..

00409A8D loc_409A8D:
00409A8D    inc     esi
00409A8E    inc     edi
00409A8F    dec     ecx
00409A90    cmp     ecx, 0FFFFFFFFh
00409A93    jz      short loc_409A9F
00409A95    mov     al, [esi]
00409A97    mov     ah, [edi]
00409A99    sub     ah, al
00409A9B    jz      short loc_409A8D
00409A9D    jmp     short loc_409AA4
00409A9F
00409A9F
00409A9F loc_409A9F:
00409A9F    push    offset aCongratulation ;"Congratulations!!!"...
00409AA4
00409AA4 loc_409AA4:
00409AA4
00409AA4    xor     eax, eax
00409AA6    push    eax
00409AA7    call    ExitProcess

..no wanie :/ czyli szukamy kolejnego backdoor'a :)... A znajdujemy go tutaj:

0040991A    mov     eax, 48544221h
0040991F    movzx   ecx, ds:byte_40F5A7
00409926    imul    ecx, 5
00409929    div     ecx            ; hmm ;)

I jeszcze taki kawaek kodu:

00409AAC loc_409AAC:                ; DATA XREF: sub_40958A+8o
00409AAC    sub     edx, edx
00409AAE    mov     eax, fs:[edx]
00409AB1    mov     esp, [eax]
00409AB3    pop     dword ptr fs:[edx]
00409AB6    pop     eax
00409AB7    mov     esi, offset dword_411203   ;hexstring(name)

Zobaczmy skd pochodzi ten kawaek:

0040958A    push    ebp
0040958B    mov     ebp, esp
0040958D    add     esp, 0FFFFFFF0h
00409590    sub     eax, eax
00409592    push    offset loc_409AAC      ; tutaj
00409597    push    dword ptr fs:[eax]
0040959A    mov     fs:[eax], esp
0040959D    push    64h             ; nIDDlgItem
0040959F    push    [ebp+hDlg]      ; hDlg
004095A2    call    GetDlgItem

..oczywicie jest to SEH, czyli obsuga wyjtkw. Nie ma sensu rozpisywa si na jej temat, po prostu jak wystpi jaki nieprzewidziany bd, to prog wywala nas do tego kawaka kodu, czyli tam gdzie musi nas wywali :), eby pokaza nam si nasz MessageBox "Good_boy".. Z tego wynika, e musimy jako wysypa proga :>, a mona to zrobi przy pomocy wspomnianego kawaka kodu:

movzx   ecx, ds:byte_40F5A7 ; do ecx musi wyldowa 0 (zero)
imul    ecx, 5              ; 0*5=0  ;P
div     ecx                 ; przy dzieleniu przez zero wystpi wyjtek :D

..tak wic ju wiemy, e w ds:byte_40F5A7 musi by 0. Do tego te wrcimy pniej, najpierw zobaczmy, co si dzieje dalej (pamitaj, e to co poniej "div ecx" ju nas nie intreresuje, bo SEH przenosi nas do 00409AAC ... A dalej rutyna :/ kolejne szyfrowania + mielonka + mielonka klucza, tylko tym razem szyfrowane jest nasze NAME, a dokadniej hexstring(name).. Na kocu wreszcie mamy porwnanie tego hexstring(name) z liczb C, czyli z wynikiem funkcji PowMod zamienion na stringa.. Heh mam nadziej, e cosik z tego zrozumiecie, wyglda to wszystko mniej wicej tak:

Hex(serial) -> IDEA -> Blowfish -> ExTEA -> Magenta -> RSA-2048 -> x
Hexstring(name) -> TEA -> RC4 -> MD5 -> CAST -> E2 -> SHA -> y

I jeli y=x to Good_Boy :]

Pozostay nam jeszcze dwie sprawy: pierwsza - co z tym  rsa-2048?! I druga - jak wrzuci 0 do ds:byte_40F5A7. Rozwizanie pierwszego problemu znajdziemy na samym pocztku crackme, jeszcze przed wywoaniem GetModuleHandle..

004093D4    call    sub_409D97     ; sprawdzamy tego call'a
004093D9    push    0
004093DB    call    GetModuleHandleA

..mamy w nim co takiego:

00409D97 sub_409D97      proc near
00409D97    mov     ebx, offset aWhat ; "WHAT"
00409D9C    add     ebx, 14h
00409D9F    push    ebx
00409DA0    call    GetFileAttributesA
00409DA5    cmp     eax, 0FFFFFFFFh
00409DA8    jz      short locret_409E24
00409DAA    push    0               ; hTemplateFile
00409DAC    push    80h             ; dwFlagsAndAttributes
00409DB1    push    3               ; dwCreationDisposition
00409DB3    push    0               ; lpSecurityAttributes
00409DB5    push    0               ; dwShareMode
00409DB7    push    80000000h       ; dwDesiredAccess
00409DBC    push    ebx             ; lpFileName
00409DBD    call    CreateFileA
00409DC2    mov     ds:hFile, eax
00409DC7    push    0               ; lpFileSizeHigh
00409DC9    push    eax             ; hFile
00409DCA    call    GetFileSize
00409DCF    cmp     eax, 81h
00409DD4    jnz     short locret_409E24
00409DD6    mov     ebx, ds:nNumberOfBytesToRead
00409DDC    push    0               ; lpOverlapped
00409DDE    push    offset nNumberOfBytesToRead ; lpNumberOfBytesRead
00409DE3    push    ebx             ; nNumberOfBytesToRead
00409DE4    push    offset Buffer   ; lpBuffer
00409DE9    push    ds:hFile        ; hFile
00409DEF    call    ReadFile
00409DF4    push    ds:hFile        ; hObject
00409DFA    call    CloseHandle
00409DFF    push    offset Buffer
00409E04    call    sub_409D89
00409E09    cmp     eax, 80h
00409E0E    jnz     short locret_409E24
00409E10    mov     ecx, 81h
00409E15    mov     esi, offset Buffer
00409E1A    mov     edi, offset aWhat ; "WHAT"
00409E1F    add     edi, 21h
00409E22    rep movsb
00409E24
00409E24 locret_409E24:             ; CODE XREF: sub_409D97+11j
00409E24               ; sub_409D97+3Dj ...
00409E24    retn

Zauwa..

00409D97    mov     ebx, offset aWhat ; "WHAT"
00409D9C    add     ebx, 14h

..w ebx znajdzie si offset ze stringiem: "RSA", ebx wrzucane jest na stos i wywoywana jest funkcja pobierajca atrybuty z parametrem nazwy pliku, czyli nasz plik musi mie nazw: "RSA" (bez ""). Nastpnie dugo pliku musi wynosi 81h (129 bajtw). Pniej dane z pliku s odczytywane i porwnywane z 80h (128d), co oznacza, e na kocu pliku musimy umieci 00. W kocu bufor z pliku wskazuje nam ESI, a bufor z naszym modulo (N) wskazuje EDI:

00409E1A    mov     edi, offset aWhat ; "WHAT"
00409E1F    add     edi, 21h   ; 33 pozycje dalej jest N

..rep movsb kopiuje 129 bajtw (mov ecx, 81h) z esi do edi.. Wraz z zerem na kocu, (najlepiej jest wyedytowa ten plik w jakim hexedytorze), czyli w takim wypadku mamy RSA-512, z tym, e moemy sami tworzy liczb N :D.. Korzystamy oczywicie z RSA-Tool. "Keysize" ustawiamy na 512, wciskamy start, "TAK", poruszamy troszku myszk, nastpnie "OK", przycisk "Generate" i teraz jedna wana rzecz. Nad polem Modulus (N), po wygenerowaniu liczby naciskamy "Exact size", po prawej stronie powinna nam si pokaza wielko N i powinna ona wynosi 512. Jeli jest np. 511 to generujemy klucz od nowa, bo jeli uyjecie klucza (N) o dugoci 511 bitw, moecie mie mae problemy z odwrceniem RSA ;) Skoro ju mamy N (512) od razu generujemy "Private Exponent", czyli D, naciskamy "Calc. D" i zapisujemy sobie wszystkie liczby. Teraz rzu okiem na ten kawaek kodu:

0040953E loc_40953E:
0040953E    cmp     ax, 0CEh
00409542    jnz     short loc_40957C
00409544    push    40h                 ; uType
00409546    push    offset aKeygenme1ByMar ; lpCaption
0040954B    push    offset aProtectionYouW ; lpText
00409550    push    [ebp+hWnd]          ; hWnd
00409553    call    MessageBoxA         ; About Box
00409558    push    [ebp+hWnd]          ; hWnd
0040955B    call    sub_409D3D     ; :]
00409560    jmp     short loc_40957E

Gdy w oknie About naciniemy OK, zostanie wywoany call, a w nim:

00409D3D sub_409D3D      proc near
00409D3D
00409D3D hWnd            = dword ptr  8
00409D3D
00409D3D    push    ebp
00409D3E    mov     ebp, esp
00409D40    push    [ebp+hWnd]
00409D43    call    GetWindowTextLengthA
00409D48    inc     eax
00409D49    push    eax
00409D4A    push    offset aKeygenme1ByMar
00409D4F    push    [ebp+hWnd]
00409D52    call    GetWindowTextA
00409D57    cmp     dword ptr ds:aKeygenme1ByMar, 79724320h
00409D61    jnz     short locret_409D76
00409D63    cmp     dword ptr ds:aKeygenme1ByMar+4, 206F7470h
00409D6D    jnz     short locret_409D76
00409D6F    mov     ds:byte_40F5A7, 0  ; nasze 0 :]
00409D76
00409D76 locret_409D76:
00409D76
00409D76    leave
00409D77    retn    4
00409D77 sub_409D3D      endp

.. Pobierane s text i dugo textu z paska tytuowego, na ktrym domylnie mamy "KeygenMe #1 by Marcus // HTBTeam". Potem pierwsze 4 znaki porwnywane s z 79724320h, czyli "yrC " i kolejne 4 znaki z 206F7470h, czyli " otp". atwo si wic domyli, e pocztek tytuu musi zaczyna si od sowa " Crypto " (bez "" i ze spacj na pocztku i na kocu!!), aby w ds:byte_40F5A7 znajdowao si 0, czyli eby wystpi wyjtek. Uff no to chyba tyle :)..

Outro

Podsumowanie:

Aby otrzyma serial z naszego name'a:

Hexstring(name) -> TEA -> RC4 -> MD5 -> CAST -> E2 -> SHA -> y

Y zamieniamy na hexstring'a, oznaczamy jako "C" i deszyfrujemy..
    C = M^E mod n           -szyfrowanie
    M = C^D mod n           -deszyfrowanie

    N = P*Q
    D = E^-1 mod ((P-1)(Q-1))

P,Q,N,D - nasze zapisane uprzednio liczby
E = 10001 (hex)

W ten sposb otrzymujemy M, w postaci stringa. Zmieniamy go na hexy i przepuszczamy przez kolejne algorytmy, tym razem deszyfrujce:

Hex(M) -> Magenta -> ExTEA -> Blowfish -> IDEA -> ..i zamieniamy na hexstring'a..

No i mamy nasz serial :)

Dodatkowo musimy mie plik "RSA" z nasz liczb N (modulo) i jeszcze ustawi pasek tytuowy na " Crypto KeygenMe #1 by Marcus // HTBTeam", po jego ustawieniu naley wcisn "About", eby w ds:byte_40F5A7 znalazo si 00.. rdeko powinno by zaczone.. Nie zawiera adnych komentarzy, bo i tak nie ma co komentowa.. :P Jeli czego nie rozumiesz - mario_crk@poczta.fm

--
mario/mbe
mario_crk@poczta.fm